#ifndef HASHFIRSTOPERANDSUBTRACTIONBOX_H_JM_20130206
#define HASHFIRSTOPERANDSUBTRACTIONBOX_H_JM_20130206
/// @file HashFirstOperandSubtractionBox.h
/// Logika operacie rozdielu R\S, kde je zahashovana relacia R.

#include "../HashActivity.h"
#include "../../RootBox.h"
#include "../HashActivityHandler.h"

namespace jm4bbx {
	/**
	 * Logika operacie rozdielu R\S, kde je zahashovana relacia R.
	 * Jedna sa o aktivitu, ktora sama neposiela vysledky na vystup ale len 
	 * upravuje podkladovu hash tabulku. Preto nie je odvodena od 
	 * {@link HashActivityBufferedOutputBox} ale priamo od {@link RootBox} a 
	 * tiez priamo implementuje rozhranie {@link HashActivity}. Vystup realizuje
	 * iny box, ktory je informovany pomocou signalov, pretoze moze zacat svoju 
	 * pracu az ked dokoncia svoju cinnost vsetky instancie tohto boxu.
	 * @see HashFirstOperandSubtractionResultBox
	 **/
	template<class HashBoxType>
	class  HashFirstOperandSubtractionBox : public HashActivity<HashBoxType>,
		public HashActivityHandler<HashBoxType>, public RootBox {
	public:

		static const  groupType INPUT_GROUP;
		static const  columnType INPUT_COLUMN;
		static const  inType IN_ARC;

		HashFirstOperandSubtractionBox(const BoxParamPack& p)
			: HashActivity(p), HashActivityHandler(nullptr, p), RootBox(p) { }
	protected:

		virtual HashActivityHanndlerType* getHashActivityHandler() override {
			return this;
		}
		/// Synchronizacia je nutna pretoze pre kazdy najdeny matchujuci zaznam
		/// sa zasahuje do hashmapy.
		virtual bool synchronize() const  override { return true; };

		// Pozaduje  HashActivity.
		virtual policyType* getData() override {
			return get_data<policyType>(INPUT_COLUMN);
		}

		virtual void initImpl() {
			// Len vstup.
			add_group(INPUT_GROUP, INPUT_COLUMN, 
				get_input_descriptors(IN_ARC));

			receive(IN_ARC, INPUT_GROUP);
		}

		/// Pokial je pocetnost zaznamu v hashmape nenulova tak dekrementuje 
		/// pocetnost zaznamu. Na vystup sa neposiela zatial nic pretoze este 
		/// mozu bezat paralelne ine boxy, ktore mozu zmenit pocetnost. 
		/// Az ked vsetci skoncia tak sa prejde mapa este raz cela a poslu sa 
		/// zvysne zaznamy na vystup to vsak uz nie je zalezitost tohto boxu.
		/// @see HashFirstOperandSubtractionResultBox
		virtual void handleRecord(TransferValueType value, 
			ExtendedHashEntry& entry) override {
				assert(entry.getCount() == 1);

				if (version_.isBagVersion()) {
					if (!entry.plainEntry.value.isEmpty()) {
						// Ak sa v hashmape nieco nachadza -> zmazem prave jeden 
						// vyskyt (resp. dekrementuj pocetnost zaznamu).
						entry.plainEntry.value.erase(
							entry.plainEntry.value.begin());
					}
				}
				else {
						entry.plainEntry.value.clear();
				}

		}

		virtual void handleNoRecord(TransferValueType value) override { }

		virtual void syncMachEtwas() {
				GroupPtr ig = getGroupPtr(INPUT_GROUP);
				doHashActivity(ig);
				sendSignalsOut(true);
				receive(IN_ARC, INPUT_GROUP);
		}
	};

	template<class hashBoxType>
	const  inType HashFirstOperandSubtractionBox<hashBoxType>::IN_ARC = 
		inType(0);

	template<class hashBoxType>
	const  columnType HashFirstOperandSubtractionBox<hashBoxType>::INPUT_COLUMN = 
		columnType(0);

	template<class hashBoxType>
	const  groupType HashFirstOperandSubtractionBox<hashBoxType>::INPUT_GROUP = 
		groupType(0);
} // namespace jm4bbx

#endif
